﻿using System;
using System.Collections.Generic;
using System.Linq;
using Medianamik.Core.Logging;
using Medianamik.Globalization;

namespace Medianamik.Core.Synchronization
{
    [CLSCompliant(false)]
    public class NodeTypeToRecordTypeConverter :
        GenericTypeToRecordTypeConverter<NodeType, NodeTypeProperty>
    {
        protected static ILogger Logger
        {
            get
            {
                return _logger
                    ?? (_logger = new ObjectFactory<ILogger>().Get("ConvertExportLogger"));
            }
        }
        private static ILogger _logger;

        //protected override bool OnConvertingToRecordTypes(IList<NodeType> typesToConvert)
        //{
        //    Logger.Trace("Début de la conversion de NodeType(s) (" + typesToConvert.Count + ") en RecordType(s).");

        //    return base.OnConvertingToRecordTypes(typesToConvert);
        //}

        protected override void OnConvertToRecordTypesEnded(IEnumerable<NodeType> typesToConvert,
            IEnumerable<RecordType> recordTypes, IEnumerable<NodeType> skippedTypesToConvert,
            CancelableMethodResults result)
        {
            switch (result)
            {
                case CancelableMethodResults.Succeeded:
                    Logger.Trace(String.Format("La conversion a réussie. Converti(s) : {0} Ignoré(s) : {1}",
                        recordTypes.Count(), skippedTypesToConvert.Count()));
                    break;
                case CancelableMethodResults.Failed:
                    Logger.Trace("La conversion a échouée.");
                    break;
                case CancelableMethodResults.Cancelled:
                    Logger.Trace("La conversion a été annulée.");
                    break;
                default:
                    break;
            }

            base.OnConvertToRecordTypesEnded(typesToConvert, recordTypes, skippedTypesToConvert,
                result);
        }

        protected override bool OnConvertingToRecordType(NodeType typeToConvert, int typeToConvertIndex,
            int typesToConvertCount)
        {
            Logger.Trace(String.Format("Début de la conversion du NodeType {0} ({1}/{2}).",
                typeToConvert.Name, typeToConvertIndex, typesToConvertCount));

            return base.OnConvertingToRecordType(typeToConvert, typeToConvertIndex,
                typesToConvertCount);
        }

        protected override void OnConvertToRecordTypeEnded(NodeType typeToConvert, RecordType recordType,
            int typeToConvertIndex, int typesToConvertCount, CancelableMethodResults result)
        {
            switch (result)
            {
                case CancelableMethodResults.Succeeded:
                    //Logger.Trace(String.Format("La conversion du type {0} ({1}/{2}) a réussie.",
                    //typeToConvert.Name, typeToConvertIndex, typesToConvertCount));
                    break;
                case CancelableMethodResults.Failed:
                    Logger.Trace(String.Format("La conversion du type {0} ({1}/{2}) a échouée.",
                    typeToConvert.Name, typeToConvertIndex, typesToConvertCount));
                    break;
                case CancelableMethodResults.Cancelled:
                    Logger.Trace(String.Format("La conversion du type {0} ({1}/{2}) a été annulée.",
                    typeToConvert.Name, typeToConvertIndex, typesToConvertCount));
                    break;
                default:
                    break;
            }

            base.OnConvertToRecordTypeEnded(typeToConvert, recordType, typeToConvertIndex,
                typesToConvertCount, result);
        }

        //protected override bool OnConvertingToRecordTypeProperties(IList<NodeTypeProperty> propertiesToConvert)
        //{
        //    Logger.Trace("Début de la conversion de NodeTypeProperty(s) (" + propertiesToConvert.Count + ") en RecordTypeProperty(s).");

        //    return base.OnConvertingToRecordTypeProperties(propertiesToConvert);
        //}

        protected override void OnConvertToRecordTypePropertiesEnded(IEnumerable<NodeTypeProperty> propertiesToConvert,
            IEnumerable<RecordTypeProperty> recordTypeProperties, IEnumerable<NodeTypeProperty> skippedTypePropertiesToConvert,
            CancelableMethodResults result)
        {
            switch (result)
            {
                case CancelableMethodResults.Succeeded:
                    //Logger.Trace(String.Format("La conversion a réussie. Converti(s) : {0} Ignoré(s) : {1}",
                    //    recordTypeProperties.Count(), skippedTypePropertiesToConvert.Count()));
                    break;
                case CancelableMethodResults.Failed:
                    Logger.Trace("La conversion a échouée.");
                    break;
                case CancelableMethodResults.Cancelled:
                    Logger.Trace("La conversion a été annulée.");
                    break;
                default:
                    break;
            }

            base.OnConvertToRecordTypePropertiesEnded(propertiesToConvert, recordTypeProperties, skippedTypePropertiesToConvert, result);
        }

        //protected override bool OnConvertingToRecordTypeProperty(NodeTypeProperty propertyToConvert,
        //    int propertyToConvertIndex, int propertiesToConvertCount)
        //{
        //    Logger.Trace(String.Format("Début de la conversion de NodeTypeProperty {0} ({1}/{2}).",
        //        propertyToConvert.Name, propertyToConvertIndex,
        //        propertiesToConvertCount));

        //    return base.OnConvertingToRecordTypeProperty(propertyToConvert, propertyToConvertIndex,
        //        propertiesToConvertCount);
        //}

        protected override void OnConvertToRecordTypePropertyEnded(NodeTypeProperty propertyToConvert,
            RecordTypeProperty recordTypeProperty, int propertyToConvertIndex,
            int propertiesToConvertCount, CancelableMethodResults result)
        {
            switch (result)
            {
                case CancelableMethodResults.Succeeded:
                    //Logger.Trace(String.Format("La conversion de la propriété {0} ({1}/{2}) a réussie.",
                    //    propertyToConvert.Name, propertyToConvertIndex, propertiesToConvertCount));
                    break;
                case CancelableMethodResults.Failed:
                    Logger.Trace(String.Format("La conversion de la propriété {0} ({1}/{2}) a échouée.",
                    propertyToConvert.Name, propertyToConvertIndex, propertiesToConvertCount));
                    break;
                case CancelableMethodResults.Cancelled:
                    Logger.Trace(String.Format("La conversion de la propriété {0} ({1}/{2}) a été annulée.",
                    propertyToConvert.Name, propertyToConvertIndex, propertiesToConvertCount));
                    break;
                default:
                    break;
            }

            base.OnConvertToRecordTypePropertyEnded(propertyToConvert, recordTypeProperty, propertyToConvertIndex, propertiesToConvertCount, result);
        }

        public override RecordType GetRecordType(NodeType genericType)
        {
            return new RecordType
               {
                   Description = genericType.Description,
                   ExtendedProperties = genericType.ExtendedProperties.Document.ToString(),
                   Id = genericType.ID,
                   IsAbstract = genericType.IsAbstract,
                   IsGenerated = genericType.IsGenerated,
                   IsIndexable = genericType.Indexable,
                   IsListable = genericType.Listable,
                   IsInheritable = genericType.IsInheritable,
                   IsSystem = genericType.IsSystem,
                   LegitimateParentRecordIds =
                       genericType.OriginalLegitimateParentNodes.Select(n => n.ID).ToList(),
                   LegitimateParentRecordTypeIds =
                       genericType.OriginalLegitimateParentTypes.Select(t => t.ID).ToList(),
                   Name = genericType.Name,
                   ParentId = genericType.ParentID,
                   LocalizedNames = Translator.GetTranslation("TypeManagement",
                    genericType.ID + "_TypeName", ConfigManager.GetMedianamikCultures().Select(
                                                     c => c.CultureInfo)),
                   Templates = genericType.Templates
                       .Select(t => new RecordTypeTemplate { WebSiteId = t.WebSiteId, TemplateId = t.TemplateId }).
                       ToList(),
                   IsVersioned = genericType.IsVersioned,
                   IsManyToMany = genericType.IsManyToMany
               };
        }

        public override RecordTypeProperty GetRecordTypeProperty(NodeTypeProperty genericProperty)
        {
            var property = new RecordTypeProperty
            {
                Description = genericProperty.Description,
                GroupName = genericProperty.GroupName,
                HasTooltip = genericProperty.HaveTooltip,
                Id = genericProperty.ID,
                IsIndexable = genericProperty.Indexable,
                IsLanguageNeutral = genericProperty.IsLanguageNeutral,
                IsLookup = genericProperty.IsLookup,
                IsRequired = genericProperty.IsRequired,
                ValueMustBeUnique = genericProperty.IsUnique,
                MaxLength = genericProperty.MaxLength,
                MinLength = genericProperty.MinLength,
                Name = genericProperty.Name,
                RegexValidation = genericProperty.ValidationRegex == null
                    ? String.Empty : genericProperty.ValidationRegex.ToString(),
                LocalizedNames = Translator.GetTranslation("TypeManagement", genericProperty.ID + "_Label",
                    ConfigManager.GetMedianamikCultures().Select(c => c.CultureInfo)),
                Flags = genericProperty.Flags.Data,
                Roles = genericProperty.Roles.Select(r => r.ToString())
            };

            //TODO: Many-to-many
            //property.MedianamikControlId = genericProperty.PrimaryMedianamikControlID;
            //property.MedianamikControlHeight = genericProperty.PrimaryMedianamikControlInfo.Height;
            //property.MedianamikControlWidth = genericProperty.PrimaryMedianamikControlInfo.Width.ToString();
            //property.RootNodeId = genericProperty.PrimaryMedianamikControlInfo.TreeRootNodeID;

            if (!genericProperty.NodeType.IsManyToMany)
            {
                property.MedianamikControlId = genericProperty.MedianamikControlID;
                property.MedianamikControlHeight = genericProperty.MedianamikControlInfo.Height;
                property.MedianamikControlWidth = genericProperty.MedianamikControlInfo.Width.ToString();
                property.RootNodeId = genericProperty.MedianamikControlInfo.TreeRootNodeID;
                property.IsManyToMany = false;
            }

            if (property.IsLookup)
            {
                property.DataTypeId = DataTypes.UniqueIdentifier;
                property.PrimaryPropertyId = genericProperty.PrimaryPropertyID;
                property.PrimaryTypeId = genericProperty.PrimaryTypeID;

                if (genericProperty.NodeType.IsManyToMany)
                {
                    property.MedianamikControlId = genericProperty.PrimaryMedianamikControlID;
                    property.MedianamikControlHeight = genericProperty.PrimaryMedianamikControlInfo.Height;
                    property.MedianamikControlWidth = genericProperty.PrimaryMedianamikControlInfo.Width.ToString();
                    property.RootNodeId = genericProperty.PrimaryMedianamikControlInfo.TreeRootNodeID;
                    property.IsManyToMany = true;
                }
            }
            else
            {
                property.DataTypeId = genericProperty.DataTypeId;
                property.RootNodeId = genericProperty.MedianamikControlInfo.TreeRootNodeID;
            }

            return property;
        }

        public override IEnumerable<NodeTypeProperty> GetNodeTypeProperties(NodeType type)
        {
            return type.Properties; //Seulement celles du type et non celles du parent
        }
    }
}